<?php
// +-------------------------------------------------------------------------------
// | DingZone [ A Rapid Development Framework For Dingtalk ]
// +-------------------------------------------------------------------------------
// | 企业相关Controller基础类 v1.0
// |
// | Copyright (c) 2014-2018 http://www.heimalanshi.com All rights reserved.
// | Author : Jie
// | Date : 2018-08-09
// +-------------------------------------------------------------------------------

namespace app\core\controller\enterprise;

use app\core\model\CacheKey;
use app\core\model\Enterprise;
use app\core\model\EnterpriseCustomize;
use app\core\model\EnterpriseDept;
use app\core\model\EnterpriseModule;
use app\core\model\EnterpriseModuleAuthority;
use app\core\model\EnterpriseSiteConfig;
use app\core\model\EnterpriseUser;
use app\core\model\SiteModule;
use app\core\controller\CoreBaseController;
use app\core\model\SiteModuleWidget;
use app\extend\sms\XFireSmsHelperImpl;
use common\XXTEAEncryption;
use ding\ApiHelper;
use sms\ResourceSmsHelperImpl;
use sms\SmsHelper;
use think\Cookie;
use think\Exception;
use think\exception\HttpResponseException;
use think\Lang;
use think\Loader;
use think\Session;

class EnterpriseBaseController extends CoreBaseController {
    /**
     * 站点配置
     *
     * @var array
     */
    protected $siteConfig;
    /**
     * 登录用户id
     *
     * @var
     */
    protected $userid;
    /**
     * 登录用户信息
     *
     * @var
     */
    protected $user;
    /**
     * 当前企业信息
     *
     * @var
     */
    protected $enterprise;
    /**
     * 当前企业id
     *
     * @var
     */
    protected $eid;
    /**
     * 当前环境
     *
     * @var
     */
    protected $env;

    /**
     * 构造函数
     *
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function __construct() {
        parent::__construct();

        // 检查登录
        $this->_checkLogin();

        // 初始化变量
        $this->_initUserEnterprise();

        // 检查url中的eid参数
        $this->_checkEid();

        // 初始化环境
        $this->_initEnv();

        // 初始化站点配置信息
        $this->_initSiteInfo();

        // 初始化自定义信息
        $this->_initCustomizeJsCss();

        // 初始化语言包
        $this->_initLangs();
    }


    /**
     * 初始化站点信息
     *
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    private function _initSiteInfo() {
        $this->siteConfig = EnterpriseSiteConfig::get($this->eid);
        $this->assign("siteConfig", $this->siteConfig);
    }

    /**
     * 检查url中如果不带eid参数，则补上。
     * 主要考虑到这种情况：A登录之后，将页面地址复制发送给B，如果链接上没有eid参数，B登录的时候不知道应该登录哪个企业
     */
    protected function _checkEid() {
        if (is_submit()) {
            // 如果是ajax或者post请求，则不处理
            return;
        }

        $eid = input("get.eid");
        if (!empty($eid)) {
            //如果指定了eid参数，则与session中的值作对比
            if ($this->eid && $this->eid != $eid) {
                // 与session中不一样，则退出登录，让用户重新登录
                $this->_clearUserSession();
                throw new HttpResponseException(
                    redirect($this->request->url(true))
                );
            }
        } else {
            //如果没有指定eid参数，则自动补充
            $url = $this->request->url(true);
            if (strrpos($url, '?') === false) {
                $url .= "?";
            } else {
                $url .= "&";
            }
            $eid = $this->_guessEid();
            $url .= "eid=" . $eid;
            throw new HttpResponseException(
                redirect($url)
            );
        }
    }

    /**
     * 猜测当前可能的eid
     *
     * @return mixed
     */
    protected function _guessEid() {
        $eid = input("get.eid");
        if (empty($eid)) {
            $eid = $this->eid;
        }
        if (empty($eid)) {
            $eid = cookie(COOKIE_CORE_CURRENT_ENTERPRISE_ID);
        }
        return $eid;
    }

    /**
     * 需要登录才能访问，未登录状态时，如果是post访问将提示需要登录，否则将会跳转至登录页面
     *
     * @return string
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    protected function _checkLogin() {
        if ($this->_isLogin()) {
            return "logged";
        } else {
            if ($this->_autoLogin()) {
                // 尝试自动登录
                return "autoLoginSuccess";
            } else {
                if (is_submit()) {
                    $this->error("请登录");
                } else {
                    // 跳转到登录页面
                    $eid = $this->_guessEid();
                    if (empty($eid)) {
                        $this->error("缺少eid参数");
                    }
                    $loginUrl = '/core/enterprise/login?eid=' . $eid;
                    if (\C::ADDONS) {
                        $loginUrl .= "&moduleName=" . $this->request->module();
                    }
                    Session::set('redirect_url_enterprise', $this->request->url());
                    throw new HttpResponseException(
                        redirect($loginUrl)
                    );
                }
            }
        }
    }


    /**
     * 通过cookie中的内容自动登录
     *
     * @return bool
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    protected function _autoLogin() {
        $eid = $this->_guessEid();
        $autoLoginToken = cookie(COOKIE_CORE_AUTO_LOGIN_TOKEN);
        $encryptUserId = cookie(COOKIE_CORE_ENTERPRISE_USERID);
        if (empty($encryptUserId) || empty($autoLoginToken) || empty($eid)) {
            return false;
        }
        //解码userid
        $userid = XXTEAEncryption::decrypt($encryptUserId, DEFAULT_DECRYPT_KEY);
        if (empty($userid)) {
            cookie(COOKIE_CORE_ENTERPRISE_USERID, null);
            cookie(COOKIE_CORE_AUTO_LOGIN_TOKEN, null);
            $this->_log("自动登录失败。userid解码失败");
            return false;
        }
        //获取用户信息
        $user = EnterpriseUser::getById($eid, $userid);
        if (empty($user)) {
            //未找到当前用户
            cookie(COOKIE_CORE_ENTERPRISE_USERID, null);
            cookie(COOKIE_CORE_AUTO_LOGIN_TOKEN, null);
            $this->_log("自动登录失败。未找到该用户");
            return false;
        }
        //检验token
        $rightAutoLoginToken = $this->_getUserAutoLoginToken($user);
        if ($autoLoginToken != $rightAutoLoginToken) {
            cookie(COOKIE_CORE_ENTERPRISE_USERID, null);
            cookie(COOKIE_CORE_AUTO_LOGIN_TOKEN, null);
            $this->_log("自动登录失败。token验证失败");
            return false;
        }

        //设置session
        $user['enterprise'] = Enterprise::get($eid);
        $this->_setUserSession($user);
        $this->_log("用户自动登录成功：" . $this->eid . ", " . $user['id'] . ", " . $user['showname']);
        return true;
    }

    /**
     * 判断是否登录
     *
     * @return boolean    true表示已经登录，false表示未登录
     */
    protected function _isLogin() {
        $user = session(SESSION_CORE_ENTERPRISE_USER);
        if (empty($user) || empty($user['id'])) {
            return false;
        }
        return true;
    }

    /**
     * 判断是否为企业管理员
     *
     * @param bool $user
     * @return bool
     */
    protected function _isEnterpriseAdmin($user = false) {
        if ($user === false) {
            $user = $this->user;
        }
        return isset($user['is_admin']) && $user['is_admin'];
    }

    /**
     * 检查企业管理员权限
     */
    protected function _checkEnterpriseAdmin() {
        $this->_checkLogin();
        if (!$this->_isEnterpriseAdmin()) {
            $this->error("您不是企业管理员，无权限访问");
        }
    }

    /**
     * 判断用户是否为模块管理员
     *
     * @param $mid
     * @param bool $user
     * @return bool
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    protected function _isModuleAdmin($mid, $user = false) {
        if ($user === false) {
            $user = $this->user;
        }
        $enterpriseModule = EnterpriseModule::getById($this->eid, $mid);
        if (empty($enterpriseModule)) {
            return false;
        }
        $adminers = $enterpriseModule['adminers'];
        foreach ($adminers as $adminer) {
            if ($adminer['type'] == 'user' && $adminer['id'] == $this->userid) {
                return true;
            }
            if ($adminer['type'] == 'dept' && $this->_inDept($adminer['id'], $user)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 检查模块管理员权限
     *
     * @param $mid
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    protected function _checkModuleAdmin($mid) {
        $this->_checkLogin();
        if (!$this->_isModuleAdmin($mid)) {
            $this->error("您不是当前模块管理员，无权限进行操作");
        }
    }

    /**
     * 检查当前用户是否为站点管理员或者企业管理员或者模块管理员
     *
     * @param $mid
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    protected function _checkEnterpriseModuleAdmin($mid) {
        $this->_checkLogin();
        if (!$this->_isEnterpriseAdmin() && !$this->_isModuleAdmin($mid)) {
            $this->error("您不是企业管理员或者当前模块管理员，无权限进行操作");
        }
    }

    /**
     * 判断当前用户是否在此部门
     *
     * @param $deptId
     * @param bool $user
     * @return bool
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    protected function _inDept($deptId, $user = false) {
        if (!$user) {
            $user = $this->user;
        }
        return EnterpriseDept::isUserInDept($this->eid, $user['id'], $deptId);
    }

    /**
     * 初始化相关变量
     */
    private function _initUserEnterprise() {
        $this->user = session(SESSION_CORE_ENTERPRISE_USER);
        $this->userid = $this->user ? $this->user['id'] : false;
        $this->eid = $this->user ? $this->user['enterprise_id'] : $this->_guessEid();
        if ($this->user && isset($this->user['enterprise'])) {
            $this->enterprise = $this->user['enterprise'];
        } else if ($this->eid) {
            $this->enterprise = Enterprise::get($this->eid);
        }
        if ($this->user && !isset($this->user['departments'])) {
            $this->user['departments'] = EnterpriseUser::getUserDepts($this->eid, $this->userid);
            $this->_setUserSession($this->user);
        }

        Cookie::forever(COOKIE_CORE_CURRENT_ENTERPRISE_ID, $this->eid);

        $this->assign("userid", $this->userid);
        $this->assign("user", $this->user);
        $this->assign("eid", $this->eid);
        $this->assign("enterprise", $this->enterprise);
    }

    /**
     * 初始化环境
     */
    protected function _initEnv() {
        $this->env = [];

        //是否为手机浏览器
        $this->env['mobile'] = $this->_isMobile();
        //钉钉手机环境
        $this->env['dingMobile'] = $this->_isDingMobile();
        //钉钉PC环境
        $this->env['dingPc'] = $this->_isDingPc();

        $this->assign("env", $this->env);
    }

    /**
     * 初始化当前页面自定义js、css
     *
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    protected function _initCustomizeJsCss() {
        if (!is_submit()) {
            //自定义样式
            $customizeJsCss = $this->_getCustomizeJsCss();
            $this->assign("_enterprise_js_css_customize", $customizeJsCss);
        }
    }

    /**
     * 初始化语言包
     *
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    protected function _initLangs() {
        //当前语言环境
        $langset = request()->langset();
        if (\C::ADDONS) {
            //如果是插件代码，不会自动加载系统默认语言，这边手动加载一下
            Lang::load([
                ROOT_PATH . 'application' . DS . 'lang' . DS . $langset . EXT,
            ]);
        }
        //加载自定义语言
        $langs = EnterpriseCustomize::getAllBy(
            $this->eid, $this->request->module(),
            $this->request->controller(),
            $this->request->action(),
            $langset,
            EnterpriseCustomize::TYPE_LANG
        );
        //从后向前配置，因为前面的优先级更高，需要最后配置
        $count = count($langs);
        for ($i = $count - 1; $i >= 0; $i--) {
            $lang = $langs[$i];
            Lang::set($lang['name'], $lang['content']);
        }
    }

    /**
     * 获取当前页面的自定义js、css配置
     *
     * @return mixed|string
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    protected function _getCustomizeJsCss() {
        $customizesJs = EnterpriseCustomize::getAllBy(
            $this->eid, $this->request->module(), $this->request->controller(),
            $this->request->action(), EnterpriseCustomize::ALL, EnterpriseCustomize::TYPE_JS
        );
        $js = '<script>';
        foreach ($customizesJs as $customize) {
            $js .= $customize['content'];
        }
        $js .= '</script>';

        $customizesCss = EnterpriseCustomize::getAllBy(
            $this->eid, $this->request->module(), $this->request->controller(),
            $this->request->action(), EnterpriseCustomize::ALL, EnterpriseCustomize::TYPE_CSS
        );
        $css = '<style>';
        foreach ($customizesCss as $customize) {
            $css .= $customize['content'];
        }
        $css .= '</style>';

        return $css . $js;
    }

    /**
     * 获取企业自定义配置项内容
     *
     * @param $name
     * @param $defaultVal
     * @return mixed
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    public function _getEnterpriseConfig($name, $defaultVal) {
        return EnterpriseCustomize::getContent($this->eid, EnterpriseCustomize::TYPE_CONFIG, $name, $defaultVal);
    }

    /**
     * 判断当前浏览器是否为手机浏览器
     *
     * @return bool
     */
    protected function _isMobile() {
        if ($this->_isDingMobile()) {
            return true;
        }
        $_SERVER['ALL_HTTP'] = isset($_SERVER['ALL_HTTP']) ? $_SERVER['ALL_HTTP'] : '';
        if (preg_match('/(up.browser|up.link|mmp|symbian|smartphone|midp|wap|phone|iphone|ipad|ipod|android|xoom)/i', strtolower($_SERVER['HTTP_USER_AGENT']))) {
            return true;
        }
        if (isset($_SERVER['HTTP_ACCEPT']) and (strpos(strtolower($_SERVER['HTTP_ACCEPT']), 'application/vnd.wap.xhtml+xml') !== false)) {
            return true;
        }
        if (isset($_SERVER['HTTP_X_WAP_PROFILE'])) {
            return true;
        }
        if (isset($_SERVER['HTTP_PROFILE'])) {
            return true;
        }
        $mobileUa = strtolower(substr($_SERVER['HTTP_USER_AGENT'], 0, 4));
        $mobileAgents = array(
            'w3c ', 'acs-', 'alav', 'alca', 'amoi', 'audi', 'avan', 'benq', 'bird', 'blac',
            'blaz', 'brew', 'cell', 'cldc', 'cmd-', 'dang', 'doco', 'eric', 'hipt', 'inno',
            'ipaq', 'java', 'jigs', 'kddi', 'keji', 'leno', 'lg-c', 'lg-d', 'lg-g', 'lge-',
            'maui', 'maxo', 'midp', 'mits', 'mmef', 'mobi', 'mot-', 'moto', 'mwbp', 'nec-',
            'newt', 'noki', 'oper', 'palm', 'pana', 'pant', 'phil', 'play', 'port', 'prox',
            'qwap', 'sage', 'sams', 'sany', 'sch-', 'sec-', 'send', 'seri', 'sgh-', 'shar',
            'sie-', 'siem', 'smal', 'smar', 'sony', 'sph-', 'symb', 't-mo', 'teli', 'tim-',
            'tosh', 'tsm-', 'upg1', 'upsi', 'vk-v', 'voda', 'wap-', 'wapa', 'wapi', 'wapp',
            'wapr', 'webc', 'winw', 'winw', 'xda', 'xda-'
        );
        if (in_array($mobileUa, $mobileAgents)) {
            return true;
        }
        if (strpos(strtolower($_SERVER['ALL_HTTP']), 'operamini') !== false) {
            return true;
        }
        if (strpos(strtolower($_SERVER['HTTP_USER_AGENT']), 'windows phone') !== false) {
            return true;
        }
        return false;
    }

    /**
     * 是否为钉钉手机环境
     *
     * @return bool
     */
    protected function _isDingMobile() {
        //Mozilla/5.0 (iPhone; CPU iPhone OS 11_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E216 AliApp(DingTalk/4.3.4) com.laiwang.DingTalk/3314110 Channel/201200 language/zh-Hans-CN
        $userAgent = $this->request->header('user-agent');
        return strpos($userAgent, 'AliApp(DingTalk') !== false;
    }

    /**
     * 是否为钉钉pc环境
     *
     * @return bool
     */
    protected function _isDingPc() {
        //Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.94 Safari/537.36 DingTalk(4.3.0-macOS) nw
        $userAgent = $this->request->header('user-agent');
        return strpos($userAgent, 'AliApp(DingTalk') === false && strpos($userAgent, 'DingTalk') !== false;
    }


    /**
     * 更新session user
     *
     * @param array $user
     */
    protected function _setUserSession($user) {
        session(SESSION_CORE_ENTERPRISE_USER, $user);

        //种下自动登录的cookie
        $autoLoginToken = $this->_getUserAutoLoginToken($user);
        Cookie::forever(COOKIE_CORE_AUTO_LOGIN_TOKEN, $autoLoginToken);
        $encryptUserId = XXTEAEncryption::encrypt($user['id'], DEFAULT_DECRYPT_KEY);
        Cookie::forever(COOKIE_CORE_ENTERPRISE_USERID, $encryptUserId);

        $this->_initUserEnterprise();
    }

    /**
     * 获取用户自动登录token
     *
     * @param $user
     * @return string
     */
    private function _getUserAutoLoginToken($user) {
        $autoLoginToken = XXTEAEncryption::encrypt($user['enterprise_id'] . "_" . $user['id'] . "_" . $user['password'], DEFAULT_DECRYPT_KEY);
        return md5($autoLoginToken);
    }


    /**
     * 清理user session
     */
    protected function _clearUserSession() {
        session(SESSION_CORE_ENTERPRISE_USER, null);
        cookie(COOKIE_CORE_AUTO_LOGIN_TOKEN, null);
        cookie(COOKIE_CORE_ENTERPRISE_USERID, null);
        $this->_initUserEnterprise();
    }

    /**
     * 判断用户是否可以访问模块
     *
     * @param $enterpriseModule
     * @param bool $user
     * @return bool
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    protected function _canAccessModule($enterpriseModule, $user = false) {
        if (!$user) {
            $user = $this->user;
        }

        $accessers = $enterpriseModule['accessers'];
        if (empty($accessers)) {
            //未设置
            return true;
        }

        if (is_string($accessers)) {
            $accessers = json_decode($accessers, true);
        }
        if ($accessers['type'] == '*') {
            //全部人员
            return true;
        }

        if ($this->_isEnterpriseAdmin() || $this->_isModuleAdmin($enterpriseModule['module_id'])) {
            //企业管理员或者模块管理员
            return true;
        }

        $list = $accessers['list'];
        if (is_string($list)) {
            $list = json_decode($list, true);
        }
        foreach ($list as $item) {
            if ($item['type'] == 'user' && $item['id'] == $user['id']) {
                return true;
            }
            if ($item['type'] == 'dept' && $this->_inDept($item['id'], $user)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 判断当前用户是否有某项权限
     *
     * @param $mid
     * @param $authorityKey
     * @param bool $user
     * @return bool
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    protected function _hasModuleAuthority($mid, $authorityKey, $user = false) {
        $authorityKey = strtolower($authorityKey);

        if ($user == false) {
            $user = $this->user;
        }

        $enterpriseModule = EnterpriseModule::getById($this->eid, $mid);
        if (!$this->_canAccessModule($enterpriseModule, $user)) {
            return false;
        }

        $moduleAuthority = EnterpriseModuleAuthority::getAll($this->eid, $mid);
        if (!isset($moduleAuthority[$authorityKey])) {
            // 此页面没有配置权限
            return true;
        }
        $authority = $moduleAuthority[$authorityKey];
        $entAdmin = $authority['value']['entAdmin'];
        $moduleAdmin = $authority['value']['moduleAdmin'];
        $other = $authority['value']['other'];

        if ($this->_isEnterpriseAdmin($user) && $entAdmin == '1') {
            return true;
        }
        if ($this->_isModuleAdmin($mid, $user) && $moduleAdmin == '1') {
            return true;
        }
        if ($other == '0') {
            return false;
        }
        if ($other == '*') {
            return true;
        }
        $other = json_decode($other, true);
        foreach ($other as $o) {
            if ($o['type'] == 'user' && $o['id'] == $user['id']) {
                return true;
            }
            if ($o['type'] == 'dept' && $this->_inDept($o['id'], $user)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 检查用户是否具有某个权限点
     *
     * @param $mid
     * @param $authorityKey
     * @param bool $user
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    protected function _checkModuleAuthority($mid, $authorityKey, $user = false) {
        if (!$this->_hasModuleAuthority($mid, $authorityKey, $user)) {
            $this->error("抱歉，您无权限访问此页面或执行此操作");
        }
    }

    /**
     * 检查用户是否是管理员或者任意部门的leader
     *
     * @param $mid
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    protected function _checkEnterpriseModuleAdminOrAnyDeptLeader($mid) {
        $this->_checkLogin();
        if (!$this->_isEnterpriseAdmin() && !$this->_isModuleAdmin($mid) && !$this->_isAnyDeptLeader()) {
            $this->error("您不是企业管理员、模块管理员或者部门leader，无权限进行操作");
        }
    }

    /**
     * 判断用户是否担任了部门leader（任意部门）
     *
     * @param bool $user
     * @return bool
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    protected function _isAnyDeptLeader($user = false) {
        if (!$user) {
            $departments = fetch($this->user, 'departments', false);
            if (!is_array($departments)) {
                $departments = EnterpriseUser::getUserDepts($this->eid, $this->userid);
            }
        } else {
            $departments = EnterpriseUser::getUserDepts($this->eid, $user['id']);
        }

        foreach ($departments as $department) {
            $leader = fetch($department, "leader", 0);
            if ($leader) {
                return true;
            }
        }
        return false;
    }

    /**
     * 获取模块信息
     *
     * @param string $mid 模块id
     * @param bool $error 如果出错是否直接中断
     * @return bool|mixed false表示获取失败
     * @throws \think\exception\DbException
     */
    protected function _getModule($mid, $error = true) {
        $enterpriseModule = EnterpriseModule::getById($this->eid, $mid);
        if (empty($enterpriseModule)) {
            if ($error) {
                // 当前企业没有安装该模块
                $this->error("无权限访问该模块");
            } else {
                return false;
            }
        }
        $module = SiteModule::getById($enterpriseModule['module_id']);
        if (empty($module)) {
            if ($error) {
                $this->error("未找到该模块");
            } else {
                return false;
            }
        }
        if ($module['status'] != SiteModule::MODULE_STATUS_ACTIVE) {
            if ($error) {
                $this->error("该模块尚未安装或已被卸载");
            } else {
                return false;
            }
        }

        return $module;
    }

    /**
     * 获取api对象
     *
     * @param $mid
     * @return ApiHelper
     * @throws \think\exception\DbException
     */
    protected function _getApiHelper($mid) {
        $module = $this->_getModule($mid, true);
        return new ApiHelper($this->enterprise, $module);
    }

    /**
     * 获取用户可见的widgets
     *
     * @param $mid
     * @param $type
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    protected function _getWidgets($mid, $type) {
        $cacheKey = CacheKey::module()->type("UserSiteModuleWidget")->tags([
            'mid' => $mid,
            'eid' => $this->eid,
            'userid' => $this->userid,
            'type' => $type
        ]);

        $widgets = $cacheKey->getValue();
        if ($widgets !== false) {
            return $widgets;
        }

        $moduleWidgets = SiteModuleWidget::getWidgets($mid);
        $widgets = [];
        foreach ($moduleWidgets as $widget) {
            if ($type == 'module') {
                if (!$widget['pushToModuleHome'] || $widget['pushToModuleHome'] == 'false') {
                    continue;
                }
            } else {
                if (!$widget['pushToGlobalHome'] || $widget['pushToGlobalHome'] == 'false') {
                    continue;
                }
            }
            if (empty($widget['authority']) || $this->_checkModuleAuthority($mid, $widget['authority'])) {
                $widgets[] = $widget;
            }
        }
        $cacheKey->setValue($widgets, 86400);
        return $widgets;
    }

    /**
     * 获取挂件信息
     *
     * @param $module
     * @param $type
     * @return array
     * @throws \think\db\exception\DataNotFoundException
     * @throws \think\db\exception\ModelNotFoundException
     * @throws \think\exception\DbException
     */
    protected function _getWidgetInfos($module, $type) {
        $mid = $module['id'];
        Loader::addNamespace("addons\\" . $module['name'],
            ROOT_PATH . "addons" . DS . $module['name'] . DS);
        Loader::addNamespace("addons\\common\\widget",
            ROOT_PATH . "addons" . DS . "common" . DS . "widget");

        $widgetInfos = [];
        $widgets = $this->_getWidgets($mid, $type);
        foreach ($widgets as $widget) {
            try {
                $packageName = "addons\\" . $module['name'] . "\\widget\\";
                $classFullName = $packageName . $widget['name'];
                if (!class_exists($classFullName)) {
                    $this->_log("class " . $classFullName . " not found.");
                    continue;
                }
                $widgetClass = new $classFullName($this->enterprise, $module, $this->user);
                $time = $widgetClass->getContentDataTime();
                if (!empty($time)) {
                    $time = date('Y-m-d H:i:s', $time);
                }
                $widgetInfos[$widget['name']] = [
                    'title' => $widgetClass->getTitle(),
                    'content' => $widgetClass->getContent(),
                    'time' => $time,
                    'type' => $widgetClass->getContentType(),
                    'width' => SiteModuleWidget::parseWidth($widget['width']),
                    'mid' => $mid
                ];
            } catch (\Exception $e) {
                $this->_log("getWidget exception: " . $e->getMessage() . "\n" . $e->getTraceAsString(), 'error');
            }
        }
        return $widgetInfos;
    }

    /**
     * 获取短信发送助手类
     *
     * @param bool $throwException
     * @return SmsHelper
     * @throws Exception
     */
    protected function _getSmsHelper($throwException = true) {
        $smsConfig = Enterprise::parseSmsconfig($this->enterprise);
        $impl = fetch($smsConfig, 'impl', 'ResourceSmsHelperImpl');
        if ($impl == 'ResourceSmsHelperImpl') {
            $smsGuestName = fetch($smsConfig, "guestName");
            $smsKey = fetch($smsConfig, "key");
            if (empty($smsGuestName) || empty($smsKey)) {
                if ($throwException) {
                    throw new Exception("本企业尚未配置短信，无法使用短信功能");
                } else {
                    return null;
                }
            }
            return new ResourceSmsHelperImpl($smsGuestName, $smsKey);
        } else if ($impl == 'XFireSmsHelperImpl') {
            $url = fetch($smsConfig, "url");
            return new XFireSmsHelperImpl($url);
        }

        if ($throwException) {
            throw new Exception("本企业尚未配置短信或短信配置错误，无法使用短信功能");
        } else {
            return null;
        }
    }

    /**
     * 需要钉钉手机APP才能打开
     */
    protected function _needViewByDingMobile() {
        if (!$this->env['dingMobile']) {
            $redirectUrl = urlencode($this->request->url(true));
            $this->redirect("/index/index/jump?from=&to=dingMobile&url=" . $redirectUrl);
        }
    }

    /**
     * 需要PC浏览器才能打开
     */
    protected function _needViewByPc() {
        if ($this->env['dingMobile'] || $this->env['mobile']) {
            $redirectUrl = urlencode($this->request->url(true));
            $this->redirect("/index/index/jump?from=mobile&to=pc&url=" . $redirectUrl);
        }
    }

    /**
     * 需要在浏览器中才能打开（钉钉桌面APP环境才会生效）
     */
    protected function _needViewByBrowser() {
        if ($this->env['dingPc']) {
            //当前是钉钉电脑端APP
            $redirectUrl = urlencode($this->request->url(true));
            $this->redirect("/index/index/jump?from=&to=browser&url=" . $redirectUrl);
        } else if ($this->env['dingMobile']) {
            //当前是手机端APP
            $redirectUrl = urlencode($this->request->url(true));
            $this->redirect("/index/index/jump?from=mobile&to=pc&url=" . $redirectUrl);
        }
    }
}